package com.edushare.common.dao;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.query.SortOrder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.edushare.common.exceptions.EduShareRuntimeException;
import com.edushare.common.orm.ORMInterface;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.Departments;
import com.edushare.common.vo.Groups;
import com.edushare.common.vo.MessageComments;
import com.edushare.common.vo.Messages;
import com.edushare.common.vo.Universities;
import com.edushare.common.vo.Users;

public class MessagesDAO extends CayenneBasedDAO {

	private static Log log = LogFactory.getLog(MessagesDAO.class);
	private String RECEIVER_ID_KEY = "receiverId";
	private String RECEIVER_TYPE_KEY = "receiverType";

	public MessagesDAO(ORMInterface ormInterface) {
		super(ormInterface);
	}
	
	
	private HashMap<String, Integer> resolveReceiverIdAndType(Object receiver, Users sender){
		HashMap<String, Integer> hm = new HashMap<String, Integer>();
		if(receiver instanceof Users && sender != null){
			hm.put(RECEIVER_ID_KEY, ((Users)sender).getUserId());
			hm.put(RECEIVER_TYPE_KEY, Messages.RECEIVER_TYPE_USER);
		}else if(receiver instanceof Users){
			hm.put(RECEIVER_ID_KEY, ((Users)receiver).getUserId());
			hm.put(RECEIVER_TYPE_KEY, Messages.RECEIVER_TYPE_USER);
		}else if(receiver instanceof CourseInstances){
			hm.put(RECEIVER_ID_KEY, ((CourseInstances)receiver).getCourseInstanceId());
			hm.put(RECEIVER_TYPE_KEY, Messages.RECEIVER_TYPE_COURSE);
		}else if(receiver instanceof Departments){
			hm.put(RECEIVER_ID_KEY, ((Departments)receiver).getDepartmentId());
			hm.put(RECEIVER_TYPE_KEY, Messages.RECEIVER_TYPE_DEPARTMENT);
		}else if(receiver instanceof Universities){
			hm.put(RECEIVER_ID_KEY,((Universities)receiver).getUniversityId());
			hm.put(RECEIVER_TYPE_KEY, Messages.RECEIVER_TYPE_UNIVERSITY);
		}else if(receiver instanceof Groups){
			hm.put(RECEIVER_ID_KEY,((Groups)receiver).getGroupId());
			hm.put(RECEIVER_TYPE_KEY, Messages.RECEIVER_TYPE_GROUP);
		}else{
			hm = null;
		}
		
		return hm;
	}
	
	public Messages createMessage(Users sender, String message, Object receiver, int privacyType){
		HashMap<String, Integer> receiverIdType = resolveReceiverIdAndType(receiver, sender);
		
		if(receiverIdType==null)
			throw new EduShareRuntimeException("Message can't be created. Please make sure that " +
					"you are passing valid object. Valid objects are Users, Courses, Departments, Universities.");		
		Messages msg = getDataContext().newObject(Messages.class);
		msg.setMessage(message);		
		msg.setReceiverId(receiverIdType.get(RECEIVER_ID_KEY));
		msg.setReceiverType(receiverIdType.get(RECEIVER_TYPE_KEY));
		msg.setUser(sender);
		msg.setPrivacyType(privacyType);
		msg.setUpdateTimestamp(new Date());
		msg.setCreationTimestamp(new Date(System.currentTimeMillis()));
		msg.setStatus(Messages.STATUS_ACTIVE);
		return msg;
	}
	
	@SuppressWarnings("unchecked")
	public
	List<Messages> getMessagesReceived(Object receiver, int pageSize, int privacyType){
		HashMap<String, Integer> receiverIdType = resolveReceiverIdAndType(receiver,null);
		if(receiverIdType==null)
			throw new EduShareRuntimeException("Message can't be created. Please make sure that " +
					"you are passing valid object. Valid objects are Users, Courses, Departments, Universities and groups.");
		if(receiver instanceof Users){
			Users user = (Users)receiver;
			return user.getAllReceivedMsgs();
		}
		
		
		Expression exp = Expression.fromString("receiverId = $rid and receiverType = $rtype " +
				"and status = $stts and privacyType <= $privacy");
		HashMap hm = new HashMap();
		hm.put("rid", receiverIdType.get(RECEIVER_ID_KEY));
		hm.put("rtype",receiverIdType.get( RECEIVER_TYPE_KEY));
		hm.put("stts", Messages.STATUS_ACTIVE);
		hm.put("privacy", privacyType);
		
		SelectQuery query = new SelectQuery(Messages.class, exp.expWithParameters(hm));
		query.addOrdering("updateTimestamp", SortOrder.DESCENDING);
		query.setPageSize(pageSize);
		
		return (List<Messages>)getDataContext().performQuery(query);
	}
	
	@SuppressWarnings("unchecked")
	public List<Messages> getUserMessages(Users receiver, int pageSize){
		Expression exp = Expression.fromString("allMessageRecipients = $usr");
		HashMap params = new HashMap();
		params.put("usr", receiver);
		SelectQuery query = new SelectQuery(Messages.class, exp.expWithParameters(params));
		query.addOrdering("updateTimestamp", SortOrder.DESCENDING);
		query.setPageSize(pageSize);
		return (List<Messages>)getDataContext().performQuery(query);
	}
	
	@SuppressWarnings("unchecked")
	public List<Messages> getUserToUserMessages(Users beingViewed, Users viewer, int pageSize, int privacyType){
//		Expression exp = Expression.fromString("receiverId = $sid or receiverId = $rid");
		Expression exp = Expression.fromString(
				"(receiverId = $viewerId and user = $viewer and allMessageRecipients=$beingViewed and receiverType = $type) or " +
				"(receiverId = $beingViewedId and user = $beingViewed and allMessageRecipients=$viewer and receiverType = $type)");
		HashMap hm = new HashMap();
		hm.put("viewerId", viewer.getUserId());
		hm.put("viewer", viewer);
		hm.put("beingViewed", beingViewed);
		hm.put("beingViewedId", beingViewed.getUserId());
		hm.put("type", Messages.RECEIVER_TYPE_USER);
		
		SelectQuery query = new SelectQuery(Messages.class, exp.expWithParameters(hm));
		query.addOrdering("updateTimestamp", SortOrder.DESCENDING);
		query.setPageSize(pageSize);
		return (List<Messages>)getDataContext().performQuery(query);
	}
	
	public void deleteMsg(Messages msg){
		getDataContext().deleteObjects(msg.getComments());
		getDataContext().deleteObject(msg);
		getDataContext().commitChanges();
	}
	
	public void deleteComment(MessageComments msg){
		getDataContext().deleteObject(msg);
		getDataContext().commitChanges();
	}
	
	public Messages getNewMessageObj(){
		return getDataContext().newObject(Messages.class);
	}
}
